#include "node.h"
#include <stdio.h>

Signal::Signal(string name){
        name_ = name;
        val_  = Z;
        FR1   = 0;
        FR0   = 0;
        V1    = 0;
        V0    = 0;
        SV1   = 0;
        SV0   = 0;
        R1    = 0;
        R0    = 0;
        RV1   = 0;
        RV0   = 0;
        BR1   = 0;
        BR0   = 0;
        P0    = 0;
        P1    = 0;
        flag0 = 0;
        flag1 = 0;
        trace = false;
}

void Signal::init(void){
        val_  = Z;
        FR1   = 0;
        FR0   = 0;
        V1    = 0;
        V0    = 0;
        SV1   = 0;
        SV0   = 0;
        R1    = 0;
        R0    = 0;
        RV1   = 0;
        RV0   = 0;
        BR1   = 0;
        BR0   = 0;
        trace = false;
}

void Signal::print(void){
	cout<<getName()<<endl;
	cout<<"P0="<<P0<<endl;
	cout<<"P1="<<P1<<endl;
	cout<<"FR0="<<FR0<<endl;
	cout<<"FR1="<<FR1<<endl;
	cout<<"BR0="<<BR0<<endl;
	cout<<"BR1="<<BR1<<endl;
	cout<<"R0="<<R0<<endl;
	cout<<"R1="<<R1<<endl;
	cout<<"RV0="<<RV0<<endl;
	cout<<"RV1="<<RV1<<endl;
	cout<<"V0="<<V0<<endl;
	cout<<"V1="<<V1<<endl;
	cout<<"SV0="<<SV0<<endl;
	cout<<"SV1="<<SV1<<endl;
	//cout<<"input:"<<inputs[0]->getName();
	//cout<<"output: "<<outputs[0]->getName()<<endl;
}

void Signal::computeP(void){

	bool qb = true;
	unsigned tmp = (inputs[0]->signature()==OUTPUT) ? 1:0;
	
	if(inputs.size()==tmp){
		P0=P1=0.5;
		return;
	}
	
	switch(inputs[tmp]->signature()){
		case NOT:
			P0 = inputs[tmp]->getInput(0)->getP1();
			P1 = inputs[tmp]->getInput(0)->getP0();
			break;
		case FLIPFLOP:
			for(int i=0; i<inputs[tmp]->outputSize(); ++i)
				if(inputs[tmp]->getOutput(i)->getName() == getName()){
					qb = false;
					P0=inputs[tmp]->getInput(1)->getP0();
					P1=inputs[tmp]->getInput(1)->getP1();
					break;
				}
			if(qb){
				P1=inputs[tmp]->getInput(1)->getP0();
				P0=inputs[tmp]->getInput(1)->getP1();
			}
			break;
		case NAND2:
			P0 = 0.25;
			P1 = 0.75;
			break;
		case NOR2:
			P0 = 0.75;
			P1 = 0.25;
			break;
		default:
			P1 = 0.5;
			P0 = 0.5;	
        }
        return;
}

string Signal::str(void) const {
	string s = name_;
	s += " inputs: ";
	for(unsigned i=0; i<inputs.size(); ++i){
		s += inputs[i]->getName();
		if(i<(inputs.size()-1))
			s += ',';
        }
	s += ")\n";
	
	s += " outputs: ";
	for(unsigned i=0; i<outputs.size(); ++i){
		s += outputs[i]->getName();
		if(i<(outputs.size()-1))
			s += ',';
        }
	s += ")\n";
	
	return s;
}

void Signal::doRestor(void){
	computeR1();
 	computeR0();
 	computeRV1();
 	computeRV0();
	float v1=V1;
	float v0=V0;
 	computeV1();
 	computeV0();
	if(V1<v1)
		V1=v1;
	if(V0<v0)
		V0=v0;

}
/*
string HybridNode::str(void) const {
	string s = "HYBRID(";
	for (unsigned i = 0; i < inputs.size(); i++) {
		s += inputs[i]->getName();
                if (i < inputs.size() - 1)
                        s += ", ";
        }
	s += ")";
	return s;
}		
*/

bool HybridNode::isActive(void) {
        
	int i = 0; 
        Value val = outputs[0]->getVal();
        vector<int*>::iterator it;
        
        for(it = OFR0.begin(); it != OFR0.end(); it++)
        {
                for(i = 0; i < inputs.size(); i++)
                        if( (*it)[i] != 2 && (*it)[i] != inputs[i]->getVal() )
                                break;
                
                if(i == inputs.size())
                {
                        visited = true;
                        outputs[0]->setVal(Zero);
                        if(val != outputs[0]->getVal())
                                return true;
                        else
                                return false;
                }
        }
        
        for(it = OFR1.begin(); it != OFR1.end(); it++)
        {
                for(i = 0; i < inputs.size(); i++)
                        if( (*it)[i] != 2 && (*it)[i] != inputs[i]->getVal() )
                                break;
                
                if(i == inputs.size())
                {
                        visited = true;
                        outputs[0]->setVal(One);
                        if(val != outputs[0]->getVal())
                                return true;
                        else
                                return false;
                }
        }
        	
	return false;
}


bool HybridNode::isBackwardActive(void) {

        int i,j,k;
        bool cond = false;
        for(i = 0; i < inputs.size(); i++)
        {
                k = 0;
                Value val = inputs[i]->getVal();
                
                if(outputs[0]->getVal() == events[2*i+0][inputs.size()-1]){
                        
                        for(j=0; j<inputs.size(); ++j)
                        {
                                if(j == i)
                                        continue;
                                else
                                        if(inputs[j]->getVal() != events[2*i+0][k++] && events[2*i+0][k++] != 2)
                                                break;
                        }
                        
                        if(j == inputs.size())
                        {
                                backwardVisited = true;
                                inputs[i]->setVal(Zero);
                                if(val != inputs[i]->getVal())
                                        cond = true;
                                else
                                        continue;
                        }
                }
                
                if(outputs[0]->getVal() == events[2*i+1][inputs.size()-1]){
                        
                        for(j=0; j<inputs.size(); ++j)
                        {
                                if(j == i)
                                        continue;
                                else
                                        if(inputs[j]->getVal() != events[2*i+1][k++] && events[2*i+1][k++] != 2)
                                                break;
                        }
                        
                        if(j == inputs.size())
                        {
                                backwardVisited = true;
                                inputs[i]->setVal(One);
                                if(val != inputs[i]->getVal())
                                        cond = true;
                                else
                                        continue;
                        }
                }
	
                int bit;
                vector<int*>::iterator it;
                for(it = extra_events.begin(); it != extra_events.end(); it++)
                {
                        bit = 0;
                        for(j = 0; j < inputs.size(); j++)
                        {
                                if(j == i)
                                        continue;
                                else
                                        if((*it)[2 + bit++] != inputs[j]->getVal() && (*it)[2 + bit++] != 2)
                                                break;
                        }
                        
                        if(j == inputs.size())
                        {
                                if((*it)[inputs.size()] == outputs[0]->getVal())
                                        if((*it)[1] == 0)
                                                inputs[(*it)[0]]->setVal(Zero);
                                        else
                                                inputs[(*it)[0]]->setVal(One);
                                
                                if(val != inputs[(*it)[0]]->getVal())
                                        cond = true;
                                else
                                        continue;
                        }
                }
        }
        
        return cond;
}

void HybridNode::forwardRestor(void){	
        
        int i,j;
        double total_v = 0.0;
        
        for(i = 0; i < inputs.size(); i++)
                total_v += inputs[i]->getV();
        
        if(total_v == 0.0)
                return;
        
        vector<int*>::iterator it;
        double FR0,FR1,total_FR0 = 0.0,total_FR1 = 0.0;
        i = 0;
        for(it = OFR0.begin(); it != OFR0.end(); it++)
        {
                FR0 = 1.0;
                for(j = 0; j < inputs.size(); j++)
                        if( (*it)[j] == 0 )
                                FR0 *= inputs[j]->getV0();
                        else if( (*it)[j] == 1 )
                                FR0 *= inputs[j]->getV1();
                        else
                                continue;
                
                //FR0 *= (double)FR0_event[i] / (double)MC_NUM;
                total_FR0 += FR0;
                //total_FR0 /= outputs[0]->getP0();
                i++;
        }
        
        i = 0;
        for(it = OFR1.begin(); it != OFR1.end(); it++)
        {
                FR1 = 1.0;
                for(j = 0; j < inputs.size(); j++)
                        if( (*it)[j] == 0 )
                                FR1 *= inputs[j]->getV0();
                        else if( (*it)[j] == 1 )
                                FR1 *= inputs[j]->getV1();
                        else
                                continue;
                
                //FR1 *= (double)FR1_event[i] / (double)MC_NUM;
                total_FR1 += FR1;
                //total_FR1 /= outputs[0]->getP1();
                i++;
        }
        
        for(i = 0; i < outputs.size(); i++)
        {
                //cout<<"RIght here Right herer!"<<endl;
                //cout<<total_FR0<<"\t"<<total_FR1<<endl;
                //cin.get();
                
                outputs[i]->setFR0(total_FR0);
                outputs[i]->setFR1(total_FR1);
                outputs[i]->doRestor();
                if(outputs[i]->getV())
                        visited = true;
        }
                
        return;
}

void HybridNode::backwardRestor(void){
        
        int i,j,cnt,bit;
        double BR,eBR,total_BR0=0.0,total_BR1=0.0;
        vector<int*>::iterator it;
        
        //if(outputs[0]->getR0()==0 && outputs[0]->getR1()==0) 
        if(outputs[0]->getV() == 0)
                return;
        
        for(i = 0; i < inputs.size(); i++)
        {
                BR = 1.0; bit = 0;
                for(j = 0; j < inputs.size(); j++)
                {
                        if(j == i)
                                continue;
                        else
                        {
                                if(events[2*i+0][bit++] == 0)
                                        BR *= inputs[j]->getV0();
                                else if(events[2*i+0][bit++] == 1)
                                        BR *= inputs[j]->getV1();
                                else
                                {
                                        bit++;
                                        continue;
                                }
                        }
                }
                
                //BR *= (double)BR_event[2*i+0]/(double)MC_NUM;
                total_BR0 += BR;
                
                cnt = 0;
                for(it = extra_events.begin(); it != extra_events.end(); it++)
                {
                        eBR = 1.0; 
                        if((*it)[0] == i && (*it)[1] == 0)
                        {
                                bit = 2;
                                for(j = 0; j < inputs.size(); j++)
                                {
                                        if(j == i)
                                                continue;
                                        else
                                        {
                                                if((*it)[bit++] == 0)
                                                        eBR *= inputs[j]->getV0();
                                                else if((*it)[bit++] == 1)
                                                        eBR *= inputs[j]->getV1();
                                                else
                                                {
                                                        bit++;
                                                        continue;
                                                }
                                        }
                                }
                                
                                //eBR *= (double)Extra_br_event[cnt]/(double)MC_NUM;
                                total_BR0 += eBR;
                        }
                        cnt++;
                }
                
                //total_BR0 /= inputs[i]->getP0();
                
                if(outputs[0]->getTraced())
                        inputs[i]->setBR0(total_BR0);
                else
                        if(events[2*i+0][inputs.size()-1] = 0)
                                inputs[i]->setBR0(total_BR0*outputs[0]->getR0()*inputs[i]->getP0());
                        else
                                inputs[i]->setBR0(total_BR0*outputs[0]->getR1()*inputs[i]->getP0());
                
                BR = 1.0; bit = 0;
                for(j = 0; j < inputs.size(); j++)
                {
                        if(j == i)
                                continue;
                        else
                        {
                                if(events[2*i+1][bit++] == 0)
                                        BR *= inputs[j]->getV0();
                                else if(events[2*i+1][bit++] == 1)
                                        BR *= inputs[j]->getV1();
                                else
                                {
                                        bit++;
                                        continue;
                                }
                        }
                }
                
                //BR *= (double)BR_event[2*i+1]/(double)MC_NUM;                
                total_BR1 += BR;
                
                cnt = 0;
                for(it = extra_events.begin(); it != extra_events.end(); it++)
                {
                        eBR = 1.0; 
                        if((*it)[0] == i && (*it)[1] == 1)
                        {
                                bit = 2;
                                for(j = 0; j < inputs.size(); j++)
                                {
                                        if(j == i)
                                                continue;
                                        else
                                        {
                                                if((*it)[bit++] == 0)
                                                        eBR *= inputs[j]->getV0();
                                                else if((*it)[bit++] == 1)
                                                        eBR *= inputs[j]->getV1();
                                                else
                                                {
                                                        bit++;
                                                        continue;
                                                }
                                        }
                                }
                                
                                //eBR *= (double)Extra_br_event[cnt]/(double)MC_NUM;
                                total_BR1 += eBR;
                        }
                        cnt++;
                }
                
                //total_BR1 /= inputs[i]->getP1();
                if(outputs[0]->getTraced())
                        inputs[i]->setBR1(total_BR1);
                else
                        if(events[2*i+1][inputs.size()-1] = 0)
                                inputs[i]->setBR1(total_BR1*outputs[0]->getR0()*inputs[i]->getP1());
                        else
                                inputs[i]->setBR1(total_BR1*outputs[0]->getR1()*inputs[i]->getP1());
                
                //cout<<"You Got Me!"<<endl;
                inputs[i]->doRestor();
                if(inputs[i]->getV())
                        backwardVisited = true;
        }
}

string InputNode::str(void) const {
	string s = "INPUT(";
	for (unsigned i = 0; i < inputs.size(); i++) {
		s += inputs[i]->getName();
                if (i < inputs.size() - 1)
                        s += ", ";
        }
	s += ")";
	return s;
}		

bool InputNode::isActive(void) {
	if(inputs[0]->isKnown()){
		visited = true;
		for(unsigned i=0; i<outputs.size(); ++i)
			outputs[i]->setVal(inputs[0]->getVal());
		return true;
	}
	return false;
}

void InputNode::forwardRestor(void) {
	if(inputs[0]->getV()==0)
		return;
	visited = true;
	for(unsigned i=0; i<outputs.size(); ++i){
		outputs[i]->setV1(inputs[0]->getV1());
		outputs[i]->setV0(inputs[0]->getV0());
	}
}

void InputNode::backwardRestor(void) {
	backwardVisited = true;
	/// to be done
}

bool InputNode::isBackwardActive(void) {
	return false;
}


string OutputNode::str(void) const {
	string s = "OUTPUT(";
	for (unsigned i = 0; i < outputs.size(); i++) {
		s += outputs[i]->getName();
                if (i < outputs.size() - 1)
                        s += ", ";
        }
	s += ")";
	return s;
}		

bool OutputNode::isActive(void) {

	if(inputs[0]->isKnown()){
		visited = true;
		for(unsigned i=0; i<outputs.size(); ++i)
			outputs[i]->setVal(inputs[0]->getVal());
		return true;
	}
	return false;
}

bool OutputNode::isBackwardActive(void) {
	return false;
}

void OutputNode::backwardRestor(void) {
	backwardVisited = true;
/// to be done
}

void OutputNode::forwardRestor(void) {
	visited = true;
/// to be done
}

string NotNode::str(void) const {
	string s = " ";
	for (unsigned i = 0; i < outputs.size(); i++) {
		s += outputs[i]->getName();
		s += " ";
		char buffer [33];
		sprintf (buffer, "%i", outputs[i]->getFlag0());
		s += buffer;
		
		s +=" ";
		sprintf (buffer, "%i", outputs[i]->getFlag1());
		s += buffer;
		
		s += "=INV(";
		s += inputs[0]->getName();
		s += " ";
	
		sprintf (buffer, "%f", inputs[0]->getP0());
		s += buffer;
		s += " ";
	
		sprintf (buffer, "%f", inputs[0]->getP1());
		s += buffer;
		s += ")\n";
	}
	return s;
}		

bool NotNode::isActive(void) {
	if(inputs[0]->isKnown()){
		visited = true;
		Value val = outputs[0]->getVal();
		for(unsigned i=0; i<outputs.size(); ++i)
			if(inputs[0]->getVal()==Zero)
				outputs[i]->setVal(One);
			else
				outputs[i]->setVal(Zero);
		if(val != outputs[0]->getVal())
			return true;
		else
			return false;
	}
	return false;
}

void NotNode::forwardRestor(void) {
	if(inputs[0]->getV()==0)
		return;
	visited = true;
	for(unsigned i=0; i<outputs.size(); ++i){
		outputs[i]->setV1( inputs[0]->getV0());
		outputs[i]->setV0( inputs[0]->getV1());
	}
}

void NotNode::backwardRestor(void) {
	if(outputs[0]->getV()==0)
		return;
	backwardVisited = true;
	for(unsigned i=0; i<inputs.size(); ++i){
		inputs[i]->setV1( outputs[0]->getV0());
		inputs[i]->setV0( outputs[0]->getV1());
	}
}
bool NotNode::isBackwardActive(void) {
	if(outputs[0]->isKnown()){
		backwardVisited = true;
		Value val = inputs[0]->getVal();
		for(unsigned i=0; i<inputs.size(); ++i)
			inputs[i]->setVal( ((outputs[0]->getVal()==Zero) ? One: (outputs[0]->getVal()==One) ? Zero:inputs[0]->getVal()));
		if(inputs[0]->getVal()!=val)
			return true;
		else
			return false;
	}
	return false;
}

string FlipflopNode::str(void) const {
	string s = " ";
	for (unsigned i = 0; i < outputs.size(); i++) {
		s += outputs[i]->getName();
		s += " ";
		char buffer [33];
		//sprintf (buffer, "%i", outputs[i]->getFlag0());
		//s += buffer;
		
		
		//s +=" ";
		//sprintf (buffer, "%i", outputs[i]->getFlag1());
		//s += buffer;	
		
		s += "=FFD(";
		s += inputs[1]->getName();
                //	s += " ";
	
		//sprintf (buffer, "val1: %i", inputs[1]->getVal());
		//s += buffer;
		
		//s += inputs[2]->getName();
		//s += " ";
	
		//sprintf (buffer, "val2: %i", inputs[2]->getVal());
		//s += buffer;
		
		s += ")\n";
	}
	
	for (unsigned i = 0; i < qBoutputs.size(); i++) {
		s += qBoutputs[i]->getName();
		s += "=NFFD(";
		s += inputs[0]->getName();
		s += ")\n";
	}
	return s;
}

//not here is input[1], input[0] is the clk!!
//if further we would like to include reset, this part will be modified
bool FlipflopNode::isActive(void) {
	if(inputs[1]->isKnown()){
		visited = true;
                return true;
	}
	return false;
}

bool FlipflopNode::isBackwardActive(void) {
	if(outputs[0]->isKnown()){
		visited = true;
                return true;
	}
	return false;
}

bool FlipflopNode::hasLoop(void){
	vector<Signal*> sigList;
	vector<int> indexList;
	indexList.push_back(index);
	sigList.push_back(outputs[0]);
	while(!sigList.empty()){
		Signal* sig = sigList.back();
		sigList.pop_back();
		for(int i=0; i<sig->outputSize(); ++i){
			if(count(indexList.begin(), indexList.end(), sig->getOutput(i)->getIndex())!=0){
				return true;
			}
			indexList.push_back(sig->getOutput(i)->getIndex());
			for(int j=0; j<sig->getOutput(i)->outputSize(); ++j)
				sigList.push_back(sig->getOutput(i)->getOutput(j));
		}
	}
	return false;
}
			
void FlipflopNode::setOutput(void){
	if(inputs[1]->getVal()==Zero){
		for(unsigned i=0; i<outputs.size(); ++i){
			outputs[i]->setVal(Zero);
		}
		for(unsigned i=0; i<qBoutputs.size(); ++i){
			qBoutputs[i]->setVal(One);
		}
		return;
	}
	
	if(inputs[1]->getVal()==One){
		for(unsigned i=0; i<outputs.size(); ++i){
			outputs[i]->setVal(One);
		}
		for(unsigned i=0; i<qBoutputs.size(); ++i){
			qBoutputs[i]->setVal(Zero);
		}
		return;
	}
	
}

void FlipflopNode::forwardRestor(void){
	if(inputs[1]->getV()!=0)
		visited = true;
	else
		return;
	for(unsigned i=0; i<outputs.size(); ++i){
		outputs[i]->setV1(inputs[1]->getV1());
		outputs[i]->setV0(inputs[1]->getV0());
	}
	
	for(unsigned i=0; i<qBoutputs.size(); ++i){
		qBoutputs[i]->setV0(inputs[1]->getV1());
		qBoutputs[i]->setV1(inputs[1]->getV0());
	}
	
	return;
}

void FlipflopNode::backwardRestor(void){
	if(outputs[0]->getV()==0)
		return;		
	if(outputs.size()){
		inputs[1]->setV1(outputs[0]->getV1());
		inputs[1]->setV0(outputs[0]->getV0());
	}
	
	if(qBoutputs.size()){
		inputs[1]->setV1(qBoutputs[0]->getV0());
		inputs[1]->setV0(qBoutputs[0]->getV1());
	}
	if(inputs[1]->getV())
                backwardVisited = true;
	return;
}

void FlipflopNode::setInput(void){
	inputs[1]->setVal(outputs[0]->getVal());
}

float FlipflopNode::getV1(void){
	float tmp=0;
	for(unsigned i=0; i<outputs.size(); ++i){
		if(tmp < outputs[i]->getV1())
			tmp = outputs[i]->getV1();
	}
	for(unsigned i=0; i<qBoutputs.size(); ++i){
		if(tmp < qBoutputs[i]->getV1())
			tmp = qBoutputs[i]->getV1();
	}
	return tmp;
}

float FlipflopNode::getV0(void){
	float tmp=0;
	for(unsigned i=0; i<outputs.size(); ++i){
		if(tmp < outputs[i]->getV0())
			tmp = outputs[i]->getV0();
	}
	for(unsigned i=0; i<qBoutputs.size(); ++i){
		if(tmp < qBoutputs[i]->getV0())
			tmp = qBoutputs[i]->getV0();
	}
	return tmp;
}

float FlipflopNode::getV(void){
	return getV1()+getV0();
}


string Nand2Node::str(void) const {
	string s = " ";
	for (unsigned i = 0; i < outputs.size(); i++) {
		s += outputs[i]->getName();
		s += " ";
		char buffer [33];
		sprintf (buffer, "%i", outputs[i]->getFlag0());
		s += buffer;
		
		s +=" ";
		sprintf (buffer, "%i", outputs[i]->getFlag1());
		s += buffer;	
		s += "=NAND2(";
		s += inputs[0]->getName();
		s += " ";
		
		sprintf (buffer, "%f", inputs[0]->getP0());
		s += buffer;
		s += " ";
		
		sprintf (buffer, "%f", inputs[0]->getP1());
		s += buffer;
		
		s += ",";
		s += inputs[1]->getName();
		s += " ";
		
		sprintf (buffer, "%i", inputs[1]->getVal());
		s += buffer;
		
		s += ")\n";
	}
	return s;
}		

bool Nand2Node::isActive(void) {
	Value val = outputs[0]->getVal();
	if((inputs[0]->getVal()==Zero)||(inputs[1]->getVal()==Zero)){
		visited = true;
		for(unsigned i=0; i<outputs.size(); ++i)
			outputs[i]->setVal(One);
		if(val != outputs[0]->getVal())
			return true;
		else
			return false;
	}
	
	if((inputs[0]->getVal()==One)&&(inputs[1]->getVal()==One)){
		visited = true;
		for(unsigned i=0; i<outputs.size(); ++i)
			outputs[i]->setVal(Zero);
		if(val != outputs[0]->getVal())
			return true;
		else
			return false;
	}
	
	if((inputs[0]->getVal()==X)||(inputs[1]->getVal()==X)){
		visited = true;
		for(unsigned i=0; i<outputs.size(); ++i)
			outputs[i]->setVal(X);
		if(val != outputs[0]->getVal())
			return true;
		else
			return false;
	}
	
	return false;
}

bool Nand2Node::isBackwardActive(void) {
	if(outputs[0]->getVal()==Zero){
		backwardVisited = true;
		Value val = inputs[0]->getVal();
		for(unsigned i=0; i<inputs.size(); ++i)
			inputs[i]->setVal(One);
		if(inputs[0]->getVal()!=val)
			return true;
		return false;
	}
	
	if((outputs[0]->getVal()==One)&&(inputs[0]->getVal()==One)){
		backwardVisited = true;
		Value val = inputs[1]->getVal();
		inputs[1]->setVal(Zero);
		if(inputs[1]->getVal()!=val)
			return true;
		return false;
	}
	
	if((outputs[0]->getVal()==One)&&(inputs[1]->getVal()==One)){
		backwardVisited = true;
		Value val = inputs[0]->getVal();
		inputs[0]->setVal(Zero);
		if(inputs[0]->getVal()!=val)
			return true;
		return false;
	}
	
	return false;
}

#ifdef CONSIDERCORR
void Nand2Node::forwardRestor(void){	
        if(correlated == 1)
        {
                if((inputs[0]->getV() + inputs[1]->getV()) == 0)
		return;
                for(unsigned i=0; i<outputs.size(); ++i){
                        outputs[i]->setFR0( inputs[0]->getV1() * inputs[1]->getV1() * (double)event_fr0_c/(double)MC_NUM );
                        outputs[i]->setFR1( inputs[0]->getV0() * inputs[1]->getV0() * 
                                            ( 1 - (double)event_fr0_c/(double)MC_NUM ) );
                        outputs[i]->doRestor();
                        if(outputs[i]->getV())
                                visited = true;
                }
        }
        else
        {
                if((inputs[0]->getV() + inputs[1]->getV()) == 0)
                        return;
                for(unsigned i=0; i<outputs.size(); ++i){
                        outputs[i]->setFR0(inputs[0]->getV1() * inputs[1]->getV1());
                        outputs[i]->setFR1(inputs[0]->getV0() + inputs[1]->getV0() 
                                           - inputs[0]->getV0() * inputs[1]->getV0());
                        outputs[i]->doRestor();
                        if(outputs[i]->getV())
                                visited = true;
                }
        }
        
        return;
}

void Nand2Node::backwardRestor(void){
        if(correlated == 1)
        {
                if(outputs[0]->getV()==0)
                        return;
                for(unsigned i=0; i<inputs.size(); ++i){
                        inputs[i]->setBR1(outputs[0]->getV0());
                        inputs[i]->setBR0(outputs[0]->getTraced() ? 
                                          ( inputs[(i+1)%2]->getV1() * (double)event_br0[i]/(double)MC_NUM * inputs[i]->getP0()) :
                                          ( outputs[0]->getR1() * inputs[(i+1)%2]->getV1() * (double)event_br0[i] / (double)MC_NUM * inputs[i]->getP0()));
                        inputs[i]->doRestor();
                        if(inputs[i]->getV())
                                backwardVisited = true;
                }
        }
        else
        {
                if(outputs[0]->getV()==0)
                        return;
                for(unsigned i=0; i<inputs.size(); ++i){
                        inputs[i]->setBR1(outputs[0]->getV0());
                        inputs[i]->setBR0(outputs[0]->getTraced() ? 
                                          (inputs[(i+1)%2]->getV1() * inputs[i]->getP0()) :
                                          (outputs[0]->getR1() * inputs[(i+1)%2]->getV1() * inputs[i]->getP0()));
                        inputs[i]->doRestor();
                        if(inputs[i]->getV())
                                backwardVisited = true;
                }
        }
}
#else
void Nand2Node::forwardRestor(void){	
	if((inputs[0]->getV() + inputs[1]->getV()) == 0)
		return;
 	for(unsigned i=0; i<outputs.size(); ++i){
 		outputs[i]->setFR0( (inputs[0]->getV1() * inputs[1]->getV1()) / 
                                    (inputs[0]->getP1() * inputs[1]->getP1()) );
 		outputs[i]->setFR1( (inputs[0]->getV0()+inputs[1]->getV0() - inputs[0]->getV0() * inputs[1]->getV0()) / 
                                    (1-inputs[0]->getP1() * inputs[1]->getP1()) );
 		outputs[i]->doRestor();
 		if(outputs[i]->getV())
 			visited = true;
        }
        return;
}

void Nand2Node::backwardRestor(void){
	if(outputs[0]->getV()==0)
		return;
	for(unsigned i=0; i<inputs.size(); ++i){
		inputs[i]->setBR1(outputs[0]->getV0()/inputs[i]->getP1());
		inputs[i]->setBR0(outputs[0]->getTraced() ? 
                                  (inputs[(i+1)%2]->getV1()) :
                                  (outputs[0]->getR1() * inputs[(i+1)%2]->getV1()));
		inputs[i]->doRestor();
		if(inputs[i]->getV())
 			backwardVisited = true;
	}
        
}
#endif

string Nand3Node::str(void) const {
	string s = " ";
	for (unsigned i = 0; i < outputs.size(); i++) {
		s += outputs[i]->getName();
		s += "=NAND3(";
		s += inputs[0]->getName();
		s += ",";
		s += inputs[1]->getName();
		s += ",";
		s += inputs[2]->getName();
		s += ")\n";
	}
	return s;
}		

string Nor2Node::str(void) const {
	string s = " ";
	for (unsigned i = 0; i < outputs.size(); i++) {
		s += outputs[i]->getName();
		s += " ";
		char buffer [33];
		sprintf (buffer, "%i", outputs[i]->getFlag0());
		s += buffer;
		
		s +=" ";
		sprintf (buffer, "%i", outputs[i]->getFlag1());
		s += buffer;	
		s += "=NOR2(";
		s += inputs[0]->getName();
		s += " ";
		sprintf (buffer, "%i", inputs[0]->getVal());
		s += buffer;
		
		s += ",";
		s += inputs[1]->getName();
		s += " ";
		sprintf (buffer, "%i", inputs[0]->getVal());
		s += buffer;
		
		s += ")\n";
	}
	return s;
}		

bool Nor2Node::isActive(void) {
	Value val = outputs[0]->getVal();
	if((inputs[0]->getVal()==One)||(inputs[1]->getVal()==One)){
		visited = true;
		for(unsigned i=0; i<outputs.size(); ++i)
			outputs[i]->setVal(Zero);
		if(val != outputs[0]->getVal())
			return true;
		else
			return false;
	}
	
	if((inputs[0]->getVal()==Zero)&&(inputs[1]->getVal()==Zero)){
		visited = true;
		for(unsigned i=0; i<outputs.size(); ++i)
			outputs[i]->setVal(One);
		if(val != outputs[0]->getVal())
			return true;
		else
			return false;
	}
	
	if((inputs[0]->getVal()==X)||(inputs[1]->getVal()==X)){
		visited = true;
		for(unsigned i=0; i<outputs.size(); ++i)
			outputs[i]->setVal(X);
		if(val != outputs[0]->getVal())
			return true;
		else
			return false;
	}
	
	return false;
}

bool Nor2Node::isBackwardActive(void) {
	if(outputs[0]->getVal()==One){
		Value val = inputs[0]->getVal();
		backwardVisited = true;
		for(unsigned i=0; i<inputs.size(); ++i)
			inputs[i]->setVal(Zero);
		if(val != inputs[0]->getVal())
			return true;
		return false;
	}
	
	if((outputs[0]->getVal()==Zero)&&(inputs[0]->getVal()==Zero)){
		backwardVisited = true;
		Value val = inputs[1]->getVal();
		inputs[1]->setVal(One);
		if(val != inputs[1]->getVal())
			return true;
		return true;
	}
	
	if((outputs[0]->getVal()==Zero)&&(inputs[1]->getVal()==Zero)){
		backwardVisited = true;
		Value val = inputs[0]->getVal();
		inputs[0]->setVal(One);
		if(val != inputs[0]->getVal())
			return true;
		return true;
	}
	
	return false;
}

#ifdef CONSIDERCORR
void Nor2Node::forwardRestor(void){
        if(correlated == 1)
        {
                if((inputs[0]->getV() + inputs[1]->getV())==0)
                        return;
                for(unsigned i=0; i<outputs.size(); ++i){
                        outputs[i]->setFR1( (inputs[0]->getV0() * inputs[1]->getV0() * (double)event_fr1_c/(double)MC_NUM) );
                        outputs[i]->setFR0( (inputs[0]->getV1() * inputs[1]->getV1() * (1 - (double)event_fr1_c/(double)MC_NUM)));

                        outputs[i]->doRestor();
                        if(outputs[i]->getV())
                                visited = true;
                }
        }
        else
        {
                if((inputs[0]->getV() + inputs[1]->getV())==0)
                        return;
                for(unsigned i=0; i<outputs.size(); ++i){
                        outputs[i]->setFR1(inputs[0]->getV0()*inputs[1]->getV0());
                        outputs[i]->setFR0(inputs[0]->getV1()+inputs[1]->getV1() - inputs[0]->getV1()*inputs[1]->getV1());
                        outputs[i]->doRestor();
                        if(outputs[i]->getV())
                                visited = true;
                }
        }
        
	return;
}

void Nor2Node::backwardRestor(void){
        if(correlated == 1)
        {
                if(outputs[0]->getV()==0)
                        return;
                backwardVisited = true;
                for(unsigned i=0; i<inputs.size(); ++i){
                        inputs[i]->setBR0( outputs[0]->getV1() );
                        inputs[i]->setBR1( outputs[0]->getTraced() ? 
                                           ( inputs[(i+1)%2]->getV0() * (double)event_br1[i]/(double)MC_NUM * inputs[i]->getP1()) :
                                           (outputs[0]->getR0() * inputs[(i+1)%2]->getV0() * (double)event_br1[i]/(double)MC_NUM) * inputs[i]->getP1());
                        inputs[i]->doRestor();
                        if(inputs[i]->getV())
                                backwardVisited = true;
                }
        }
        else
        {
                if(outputs[0]->getV()==0)
                        return;
                backwardVisited = true;
                for(unsigned i=0; i<inputs.size(); ++i){
                        inputs[i]->setBR0(outputs[0]->getV1());
                        inputs[i]->setBR1(outputs[0]->getTraced() ? 
                                          (inputs[(i+1)%2]->getV0() * inputs[i]->getP1()) :
                                          (outputs[0]->getR0()* inputs[(i+1)%2]->getV0() 
                                           * inputs[i]->getP1()));
                        inputs[i]->doRestor();
                        if(inputs[i]->getV())
                                backwardVisited = true;
                }
        }
        
        return;
}
#else
void Nor2Node::forwardRestor(void){
	if((inputs[0]->getV() + inputs[1]->getV())==0)
		return;
	for(unsigned i=0; i<outputs.size(); ++i){
		outputs[i]->setFR1((inputs[0]->getV0()*inputs[1]->getV0())/
                                   outputs[i]->getP1());
		outputs[i]->setFR0((inputs[0]->getV1()+inputs[1]->getV1() - inputs[0]->getV1()*inputs[1]->getV1()) /
                                   outputs[i]->getP0());
		outputs[i]->doRestor();
		if(outputs[i]->getV())
                        visited = true;
 	}
	return;
}

void Nor2Node::backwardRestor(void){
	if(outputs[0]->getV()==0)
		return;
	backwardVisited = true;
	for(unsigned i=0; i<inputs.size(); ++i){
		inputs[i]->setBR0(outputs[0]->getV1()/inputs[i]->getP0());
		inputs[i]->setBR1(outputs[0]->getTraced() ? 
                                  (inputs[(i+1)%2]->getV0()) :
                                  (outputs[0]->getR0()* inputs[(i+1)%2]->getV0()));
		inputs[i]->doRestor();
		if(inputs[i]->getV())
 			backwardVisited = true;
	}
	return;
}
#endif
	
string Nor3Node::str(void) const {
	string s = " ";
	for (unsigned i = 0; i < outputs.size(); i++) {
		s += outputs[i]->getName();
		s += "=NOR3(";
		s += inputs[0]->getName();
		s += ",";
		s += inputs[1]->getName();
		s += ",";
		s += inputs[2]->getName();
		s += ")\n";
	}
	return s;
}		
